package com.yutian.selfservice.support.dict;

import com.yutian.selfservice.support.utils.ReflectionUtils;
import com.yutian.selfservice.support.utils.SpringUtil;
import lombok.Builder;
import lombok.Data;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 数据字典组件
 *
 * @author zuoqiwen
 * @version 1.0
 * @date 2021-09-01
 */
@Component
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class DictPlugin implements Interceptor {
    /**
     * 该对象由于间接引入了mapper 必须lazy注入 否则会引起MapperAutoConfiguration的循环依赖
     */
    @Autowired
    @Lazy
    private DictConfig dictConfig;
    private static final Map<Class, List<CacheField>> filed = new ConcurrentHashMap();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        List list = (List) invocation.proceed();
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }
        Class clazz = list.get(0).getClass();
        if (ReflectionUtils.isAnnotationFromClass(clazz, Dict.class)) {
            if (filed.get(clazz) == null) {
                init(clazz);
            }
            filed.get(clazz).forEach(x -> list.forEach(y -> ReflectionUtils.setValue(x.getField(), y, dictConfig.getValue(x.getDictType(), (String) ReflectionUtils.getValue(x.getField(), y)))));
        }
        return list;
    }

    private void init(Class clazz) {
        List<CacheField> cacheFields = Arrays.stream(clazz.getDeclaredFields()).filter(x -> ReflectionUtils.isAnnotationFromClass(x, Dict.class))
                .map(x -> CacheField.builder().field(x).dictType(x.getAnnotation(Dict.class).value()).build()).collect(Collectors.toList());
        filed.put(clazz, cacheFields);
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    @Data
    @Builder
    private static class CacheField {
        private Field field;
        private String dictType;
    }
}
